package chat.client;

import java.io.IOException;
import java.net.Socket;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.TreeMap;
import java.util.Vector;

import javax.sound.midi.Receiver;
import javax.swing.ImageIcon;
import javax.swing.JEditorPane;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;

import chat.ui.ChatHandler;
import chat.ui.GroupChatWindow;
import chat.user.*;

public class ClientMain implements Runnable {

	private static Queue<Request> InMessageList = new LinkedList<Request>();
	private static Queue<Request> OutMessageList = new LinkedList<Request>();
	private Socket fromserver;
	private GroupChatWindow chat_window;
	Object sync = new Object();
	private ClientReceiver receiver;

	public ClientMain(GroupChatWindow chat) {

		chat_window = chat;

		try {
			fromserver = new Socket("localhost", 4444);
			
			receiver = new ClientReceiver(fromserver);
			new Thread(new ClientRequestor(fromserver)).start();
			new Thread(receiver).start();

		} catch (IOException e) {

			e.printStackTrace();
			System.out.println("Cannot connect to server");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	@Override
	public synchronized void run() {

		try {

			for (;; Thread.sleep(500)) { // used to improve performance

				// while (true) {

				synchronized (sync) {

					while (getInMessageCount() > 0) {

						// for ( ; getInMessageCount()>0; ){

						Request r = getInMessage();

						if (r instanceof RequestAuth) {
							ClientMain.addOutMessage(MessageCreator
									.createUpdateGroupMessage(chat_window
											.getUser()));
							MessageCreator.requestUserGroupUpdate(chat_window
									.getUser());

						} else if (r instanceof RequestDisconnect) {
							
							//disconnect();
							
						}
						else if (r instanceof RequestGroupUpdate) {

							Vector<String> g_names = ((RequestGroupUpdate) r)
									.getGroupNames();

							Vector<String> current_group_list = chat_window
									.getGroupList();

							updateGroups(g_names, current_group_list);

						} else if (r instanceof RequestMessage) {
							chat_window.getChatPanel().getChatHandler().setTextFromMessageToGroup(
									((RequestMessage) r).getMessage(),
									chat_window.getChat(), chat_window
											.getUser().getRelatedGroup(),((RequestMessage) r)
											.getFromUser());

						} else if (r instanceof RequestNewGroup) {

							chat_window.addNewItem(((RequestNewGroup) r)
									.getGroup());

						} else if (r instanceof RequestStatusUpdate) {
							
							RequestStatusUpdate response = (RequestStatusUpdate) r;
							
							chat_window.getNode(response.getFromUser()).setFlagIcon(response.getStatus());
							chat_window.treeReload();
						}
						else if (r instanceof RequestUserGroupUpdate) {

							RequestUserGroupUpdate response = (RequestUserGroupUpdate) r;

							Map<String, Vector<User>> u_g_list = response
									.getUserGroupList();

							for (Map.Entry<String, Vector<User>> entry : u_g_list
									.entrySet()) {

								String group = entry.getKey();

								Vector<User> user_list = entry.getValue();

								for (User user : user_list) {

									chat_window.addUserItem(group, user);

								}
							}

						} else if (r instanceof RequestChangeUserGroup) {

							RequestChangeUserGroup response = (RequestChangeUserGroup) r;

							chat_window.removeUserItem(response.getOldGroup(),
									response.getChangedUser().getUserName());
							chat_window.addUserItem(response.getNewGroup(),
									response.getChangedUser());
						} else if (r instanceof RequestConnectGroup) {

							RequestConnectGroup response = (RequestConnectGroup) r;
							
							String old_group = chat_window.getUser().getRelatedGroup();
							
							User user = (User) chat_window.getUser().clone();

							chat_window.getChat().removeContact(user.getRelatedGroup());
							
							chat_window.getChat().addContact(response.getGroup());

							chat_window.removeUserItem(chat_window.getUser()
									.getRelatedGroup(), chat_window.getUser()
									.getUserName());

							MessageCreator.requestChangedGroupUser(user,
									response.getGroup(), old_group);

							chat_window.getUser().updateRelatedGroup(
									response.getGroup());

							chat_window.addUserItem(response.getGroup(),
									response.getUser());

						} else if (r instanceof RequestUserMessage) {

						/*	JEditorPane area = chat_window
									.getChat()
									.getTabbedPanel()
									.getUserTextArea(
											((RequestUserMessage) r)
													.getDestinationUser());
*/
							chat_window.getChat().addContact(
									((RequestUserMessage) r)
									.getDestinationUser());
							
							chat_window.getChatPanel().getChatHandler().setTextFromMessageToGroup(
									((RequestUserMessage) r).getMessage(),
									chat_window.getChat(),
									((RequestUserMessage) r)
											.getDestinationUser(),
											((RequestUserMessage) r).getDestinationUser());

						} else if (r instanceof RequestRemoveGroup) {

							RequestRemoveGroup response = (RequestRemoveGroup) r;

							if (response.isAllowed()) {

								chat_window.removeItem(response.getGroup());

							} else {

								final ImageIcon icon = new ImageIcon("red1.jpg");
								JOptionPane
										.showMessageDialog(
												null,
												"Group cannot be deleted. It has connected users OR it is General",
												"Error",
												JOptionPane.INFORMATION_MESSAGE,
												icon);
							}

						}
						ClientMain.removeInMessage(r);
					}
				}
			}
				
		} catch (Exception e) {

			e.printStackTrace();
		}
		/*finally{
			try {
				fromserver.shutdownInput();
				fromserver.shutdownOutput();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}*/
	}

	public static boolean addInMessage(Request r) {

		return InMessageList.add(r);
	}

	public static boolean removeInMessage(Request r) {

		return InMessageList.remove(r);
	}

	public static boolean addOutMessage(Request r) {

		return OutMessageList.add(r);
	}

	public static boolean removeOutMessage(Object r) {

		return OutMessageList.remove(r);
	}

	public static Request getInMessage() {

		return InMessageList.peek();
	}

	public static Request getOutMessage() {

		return OutMessageList.peek();
	}

	public static int getInMessageCount() {
		return InMessageList.size();
	}

	public static int getOutMessageCount() {
		return OutMessageList.size();
	}

	public synchronized void updateGroups(Vector<String> incoming_groups,
			Vector<String> upcoming_groups) {

		for (String c : upcoming_groups) {

			boolean isInList = false;

			for (String n : incoming_groups) {
				if (c.equalsIgnoreCase(n)) {
					isInList = true;
				}
			}
			if (isInList) {
				isInList = false;
			} else {
				chat_window.removeItem(c);
			}
		}
		for (String n : incoming_groups) {
			if (!n.equalsIgnoreCase("ROOT")) {
				chat_window.addNewItem(n);
			}
		}
	}
	
	private void disconnect() throws Exception{
		
		
		fromserver.shutdownInput();
		fromserver.shutdownOutput();
		receiver.disconnect();
		fromserver.close();
		
	}
}
